package com.faxsun.admin.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.broadleafcommerce.common.money.Money;
import org.broadleafcommerce.common.payment.PaymentTransactionType;
import org.broadleafcommerce.common.payment.PaymentType;
import org.broadleafcommerce.common.util.TransactionUtils;
import org.broadleafcommerce.core.order.domain.Order;
import org.broadleafcommerce.core.order.domain.OrderItem;
import org.broadleafcommerce.core.order.service.OrderService;
import org.broadleafcommerce.core.payment.domain.OrderPayment;
import org.broadleafcommerce.core.payment.domain.PaymentTransaction;
import org.broadleafcommerce.core.payment.service.OrderPaymentService;
import org.broadleafcommerce.core.pricing.service.exception.PricingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.faxsun.admin.web.domain.CreateRefundResponseEntity;
import com.faxsun.admin.web.domain.ResponseEntity;
import com.faxsun.admin.web.domain.form.RefundInfoForm;
import com.faxsun.admin.web.domain.util.ResponseConventor;
import com.faxsun.api.service.FaxsunService;
import com.faxsun.core.order.dao.PaymentTransactionDao;
import com.faxsun.core.order.domain.FSOrderImpl;
import com.faxsun.core.order.domain.FSOrderItemImpl;
import com.faxsun.core.order.service.FSOrderService;
import com.faxsun.core.order.service.type.FSInternalOrderStatus;
import com.faxsun.model.response.Response;
import com.faxsun.model.response.result.CreateRefundResult;

@Service("refundService")
public class RefundServiceImpl implements RefundService {

	private static final Log LOG = LogFactory.getLog(RefundServiceImpl.class);

	@Resource(name = "blOrderService")
	protected OrderService orderService;

	@Resource(name = "fsRefundDao")
	protected PaymentTransactionDao refundTransactionDao;

	@Resource(name = "blOrderPaymentService")
	protected OrderPaymentService orderPaymentService;

	/**
	 * 列出所有退货订单
	 */
	@Override
	public List<Order> listToBeRefund() {
		FSOrderService fsOrderService = (FSOrderService) orderService;

		List<Order> orders = fsOrderService
				.retrieveOrderByInternalStatus(FSInternalOrderStatus.REFUND_PROCESSING);
		List<Order> ordersRequest = fsOrderService
				.retrieveOrderByInternalStatus(FSInternalOrderStatus.REFUND_REQUEST);

		ordersRequest.addAll(orders);
		return ordersRequest;
	}

	/**
	 * 列出所有退款记录
	 */
	@Override
	public List<PaymentTransaction> listRefundedTransaction() {

		return refundTransactionDao.readAllRefundTransactions();
	}

	@Override
	public List<PaymentTransaction> listRefundedTransactionByOrder(
			String orderId) {

		List<PaymentTransaction> result = new ArrayList<PaymentTransaction>();
		try {
			Order order = this.orderService.findOrderById(Long
					.parseLong(orderId));
			List<OrderPayment> payments = order.getPayments();
			for (OrderPayment payment : payments) {
				result.addAll(payment
						.getTransactionsForType(PaymentTransactionType.REFUND));
			}
		} catch (Exception e) {
			LOG.error("", e);
		}
		return result;
	}

	/**
	 * 列出所有退款完成订单
	 */
	@Override
	public List<Order> listRefundOrder() {
		FSOrderService fsOrderService = (FSOrderService) orderService;

		List<Order> orders = fsOrderService
				.retrieveOrderByInternalStatus(FSInternalOrderStatus.REFUND_COMPLETE);

		return orders;
	}

	@Override
	@Transactional(value = TransactionUtils.DEFAULT_TRANSACTION_MANAGER)
	public ResponseEntity executeRefund(RefundInfoForm refundInfoForm) {
		Order order = refundInfoForm.getOrder();
		order = orderService.findOrderByOrderNumber(order.getOrderNumber());
		BigDecimal amount = refundInfoForm.getAmount();
		BigDecimal availableAmount = this.calulateRemainingRefundAmount(order);

		ResponseEntity retVal = CreateRefundResponseEntity.SUCC;
		if (availableAmount.compareTo(new BigDecimal(0.00)) != 0) {

			retVal = invokeService(order, amount);
			if (retVal instanceof CreateRefundResponseEntity && retVal.isSucc()) {
				//退款操作成功
				// 更新数据库中订单状态
				BigDecimal remaining = calulateRemainingRefundAmount(order);
				BigDecimal zero = new BigDecimal(0.00);
				if (remaining.compareTo(zero) == 0) {
					// 退款完毕，更新状态
					FSOrderImpl fsOrder = (FSOrderImpl) order;
					fsOrder.setInternalStatus(FSInternalOrderStatus.REFUND_COMPLETE);
					try {
						orderService.save(order, false);
					} catch (PricingException e) {
						e.printStackTrace();
					}
				}
			}
		}
		return retVal;
	}

	/**
	 * 调用退款服务封装接口
	 * 
	 * 1. 持久化退款交易记录 2. 从 <code>PaymentType.THIRD_PARTY_ACCOUNT</code>
	 * 记录中查找第一条处于激活状态的记录 3. 解析seller_id和pid 4. 更新退款交易记录
	 * 
	 * @param order
	 * @param amount
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private ResponseEntity invokeService(Order order, BigDecimal amount) {
		try {
			List<OrderPayment> payments = order.getPayments();
			int count = 0;

			String pid = "";
			String sellerOrderId = "";
			int refundAmount = amount.multiply(new BigDecimal(100)).intValue();
			String sellerRefundId = "";

			PaymentTransaction refundTransaction = this.orderPaymentService
					.createTransaction();
			refundTransaction.setAmount(new Money(amount));
			refundTransaction.setSuccess(Boolean.FALSE);
			refundTransaction.setType(PaymentTransactionType.REFUND);
			refundTransaction.setArchived('Y');

			for (OrderPayment payment : payments) {
				if (payment.isActive()
						&& payment.getType().equals(
								PaymentType.THIRD_PARTY_ACCOUNT)) {
					count++;
					if (count == 1) {
						List<PaymentTransaction> transactions = payment
								.getTransactionsForType(PaymentTransactionType.AUTHORIZE_AND_CAPTURE);

						// 先将退款记录写入数据库，无response，默认失败
						refundTransaction.setOrderPayment(payment);
						refundTransaction = refundTransactionDao
								.save(refundTransaction);
						payment.addTransaction(refundTransaction);
						payment = orderPaymentService.save(payment);

						for (PaymentTransaction transaction : transactions) {
							if (transaction.isActive()) {
								// FIXME: 如果有多个处于激活状态如何处理
								// 当前仅取第一个激活状态的记录
								String rawResponse = transaction
										.getRawResponse();
								ObjectMapper om = new ObjectMapper();
								Map<String, Map<String, String>> maps;
								maps = om.readValue(rawResponse, Map.class);
								Map<String, String> paras = maps
										.get("parameters");
								pid = paras.get("pid");
								sellerOrderId = paras.get("order_id");

								sellerRefundId = refundTransaction.getId()
										.toString();

								break;
							}
						}
					}
				}
			}

			//fixbug: order payment is not existed in test environment, which should not appear in production
			if(refundTransaction.getOrderPayment()==null){
				return ResponseConventor.EXCEPTION;
			}
			Response<CreateRefundResult> response = FaxsunService.createRefund(
					pid, sellerOrderId, refundAmount, sellerRefundId);

			ObjectMapper mapper = new ObjectMapper();
			// 将退款结果保存到数据库
			refundTransaction.setRawResponse(mapper
					.writeValueAsString(response));
			boolean isSucc = response.getBaseResponse().getRetCode() == 200;
			refundTransaction.setSuccess(isSucc);
			if (isSucc) {
				// 若退款成功，记录标记为Active
				refundTransaction.setArchived('N');
			}
			refundTransactionDao.save(refundTransaction);

			return ResponseConventor.buildFromResponse(response,
					CreateRefundResponseEntity.class);
		} catch (Exception e) {
			LOG.error("There is something wrong when send refund requests", e);
			return ResponseConventor.EXCEPTION;
		}

	}

	@Override
	public Order readOrderByOrderNumber(String orderNumber) {
		Order order = this.orderService.findOrderByOrderNumber(orderNumber);
		return order;
	}

	@Override
	public Order createOrder() {
		FSOrderImpl order = new FSOrderImpl();
		order.setTotal(new Money(0));
		return order;
	}

	public BigDecimal calulateRemainingRefundAmount(Order order) {
		BigDecimal availableAmount = new BigDecimal(0.00);
		availableAmount.setScale(2);
		List<OrderItem> items = order.getOrderItems();
		for (OrderItem item : items) {
			FSOrderItemImpl i = (FSOrderItemImpl) item;
			FSInternalOrderStatus itemStatus = i.getStatus();
			if (itemStatus != null
					&& (itemStatus.equals(FSInternalOrderStatus.REFUND_REQUEST) || (itemStatus
							.equals(FSInternalOrderStatus.REFUND_PROCESSING)))) {
				availableAmount = availableAmount.add(i.getRetailPrice()
						.getAmount().multiply(new BigDecimal(i.getQuantity())));
			}
		}

		// 减去已退款项
		List<OrderPayment> payments = order.getPayments();
		for (OrderPayment payment : payments) {
			List<PaymentTransaction> refunds = payment
					.getTransactionsForType(PaymentTransactionType.REFUND);
			for (PaymentTransaction refund : refunds) {
				if (refund.isActive()) {
					availableAmount = availableAmount.subtract(refund
							.getAmount().getAmount());
				}
			}
		}
		return availableAmount;
	}
}
